package com.lyf.scm.plan.domain.service.impl;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.github.pagehelper.PageInfo;
import com.lyf.scm.common.constants.BigDataEsConstants;
import com.lyf.scm.common.enums.*;
import com.lyf.scm.common.model.ExcelExportDataDTO;
import com.lyf.scm.common.util.AdvancedSearchUtil;
import com.lyf.scm.common.util.ExcelExportUtil;
import com.lyf.scm.common.util.date.MyDateUtil;
import com.lyf.scm.common.util.style.GeneralCellWriteHandler;
import com.lyf.scm.plan.api.dto.*;
import com.lyf.scm.plan.domain.remote.basedata.dto.AreaLevelDTO;
import com.lyf.scm.plan.domain.remote.basedata.dto.ChannelDTO;
import com.lyf.scm.plan.domain.remote.basedata.dto.StoreDTO;
import com.lyf.scm.plan.domain.remote.basedata.facade.BaseDataFacade;
import com.lyf.scm.plan.domain.remote.item.dto.SkuUnitDTO;
import com.lyf.scm.plan.domain.remote.item.facade.ItemCoreFacade;
import com.lyf.scm.plan.domain.remote.purchase.dto.PlanPoInfoDTO;
import com.lyf.scm.plan.domain.remote.purchase.dto.PlanPoQueryDTO;
import com.lyf.scm.plan.domain.remote.purchase.facade.PurchaseFacade;
import com.lyf.scm.plan.domain.remote.stock.facade.StockCoreFacade;
import com.lyf.scm.plan.domain.repository.RequirementConfirmationRepository;
import com.lyf.scm.plan.domain.repository.RoleAuthorityAreaRepository;
import com.lyf.scm.plan.domain.service.CommonService;
import com.lyf.scm.plan.domain.service.RedisCacheService;
import com.lyf.scm.plan.domain.service.RequirementPlanService;
import com.lyf.scm.plan.insfrastructure.db.dataobject.RequirementConfirmationDO;
import com.lyf.scm.plan.insfrastructure.db.dataobject.es.SalesPlanEsEntity;
import com.lyf.scm.plan.insfrastructure.db.dataobject.es.TestEsEntity;
import com.rome.arch.core.exception.RomeException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.script.Script;
import org.elasticsearch.search.aggregations.AbstractAggregationBuilder;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.composite.*;
import org.elasticsearch.search.aggregations.bucket.terms.InternalTerms;
import org.elasticsearch.search.aggregations.bucket.terms.LongTerms;
import org.elasticsearch.search.aggregations.bucket.terms.StringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.aggregations.metrics.avg.InternalAvg;
import org.elasticsearch.search.aggregations.metrics.sum.InternalSum;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.ScrolledPage;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.IndexQuery;
import org.springframework.data.elasticsearch.core.query.IndexQueryBuilder;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.SearchQuery;
import org.springframework.stereotype.Service;

import javax.annotation.Nullable;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

import static com.lyf.scm.common.constants.CommonConstants.REDIS_CACHE_REQUIREMENT;
import static com.lyf.scm.common.enums.RequirementPlanEnum.*;
import static com.lyf.scm.common.util.BatchHandlerUtil.splitTo;
import static java.util.stream.Collectors.groupingBy;
import static org.elasticsearch.index.query.QueryBuilders.matchQuery;
import static org.elasticsearch.index.query.QueryBuilders.rangeQuery;

/**
 * 需求计划
 *
 * @author wangchlei
 * @date 2020/10/26
 */
@Slf4j
@Service
public class RequirementPlanServiceImpl implements RequirementPlanService {
    @Resource
    private ElasticsearchTemplate elasticsearchTemplate;
    @Resource
    private RequirementConfirmationRepository requirementConfirmationRepository;
    @Resource
    private BaseDataFacade baseDataFacade;
    @Resource
    private ItemCoreFacade itemCoreFacade;
    @Resource
    private StockCoreFacade stockCoreFacade;
    @Resource
    private PurchaseFacade purchaseFacade;
    @Resource
    private CommonService commonService;
    @Resource
    private RoleAuthorityAreaRepository roleAuthorityAreaRepository;
    @Resource
    private RedisCacheService redisCacheService;

    @Override
    public PageInfo<RequirementPlanInfoDTO> listWeekBySelective(RequirementPlanDTO requirementPlanDTO) {
        //获取es查询条件,同时标记完搜索条件查询细粒度
        SearchQuery searchQuery = this.getSearchQuery(requirementPlanDTO);
        //查询es
        Aggregations aggregations = elasticsearchTemplate.query(searchQuery, SearchResponse::getAggregations);
        //创建分页信息
        PageInfo<RequirementPlanInfoDTO> pageInfo = new PageInfo<>();
        //获取结果(已分页)
        List<RequirementPlanInfoDTO> pageResult = this.dealResultPage(aggregations, requirementPlanDTO, pageInfo);
        if (CollectionUtils.isEmpty(pageResult)) {
            return pageInfo;
        }
        int elementSize = requirementPlanDTO.getDateList().size();
        //处理前端名称的信息展示--渠道，仓库，区域，品类
        this.setGeneralInfo(pageResult, requirementPlanDTO);
        //设置预约在途采购量和未履约采购量
        this.setReservePurchaseQty(pageResult, requirementPlanDTO, elementSize);
        //TODO 实际销量
        this.setActualQty(pageResult, requirementPlanDTO, elementSize);
        //返回分页结果
        pageInfo.setList(pageResult);
        return pageInfo;
    }

    private void setActualQty(List<RequirementPlanInfoDTO> pageResult, RequirementPlanDTO requirementPlanDTO, int elementSize) {
        List<BigDecimal> list = new ArrayList<>();
        for (int i = 0; i < elementSize; i++) {
            list.add(BigDecimal.ZERO);
        }
        for (RequirementPlanInfoDTO item : pageResult) {
            item.setActualSalesQty(list);
        }
    }

    /**
     * 更新供应链确认量
     *
     * @param requirementConfirmationDTOs
     * @return void
     **/
    @Override
    public void updateConfirmQty(List<RequirementConfirmationDTO> requirementConfirmationDTOs, Long unitType) {
        if (CollectionUtils.isEmpty(requirementConfirmationDTOs)) {
            return;
        }
        long nowDate = DateUtil.beginOfWeek(new Date()).getTime();
        final long SCROLL_TIMEOUT = 5 * 60 * 1000;
        SearchQuery searchQuery;
        List<SalesPlanEsEntity> tmpList;
        BigDecimal tmpTotal;
        BigDecimal tmpConfirmQty;
        List<IndexQuery> queryList = new ArrayList<>();
        ScrolledPage<SalesPlanEsEntity> scroll;
        //获取单位转换率
        Map<String, SkuUnitDTO> skuUnitDTOMap = null;
        if (!SkuUnitTypeEnum.BASIS_UNIT.getUnitType().equals(unitType)) {
            Set<String> skuCodes = new HashSet<>();
            List<UnitRateQueryDTO> unitRateQueryDTOs = new ArrayList<>();
            UnitRateQueryDTO unitRateQueryDTO;
            for (RequirementConfirmationDTO item : requirementConfirmationDTOs) {
                if (skuCodes.contains(item.getSkuCode())) {
                    continue;
                }
                skuCodes.add(item.getSkuCode());
                unitRateQueryDTO = new UnitRateQueryDTO();
                unitRateQueryDTO.setSkuCode(item.getSkuCode());
                unitRateQueryDTO.setFromUnitType(unitType);
                unitRateQueryDTO.setToUnitType(SkuUnitTypeEnum.BASIS_UNIT.getUnitType());
                unitRateQueryDTOs.add(unitRateQueryDTO);
            }
            skuUnitDTOMap = redisCacheService.getUnitConversionRatio(unitRateQueryDTOs);
        }
        for (RequirementConfirmationDTO item : requirementConfirmationDTOs) {
            //判断是否符合编辑时间
            if (item.getPlanStartDate().getTime() < nowDate) {
                continue;
            }
            //构建查询语句
            searchQuery = this.getConfirmSearchQuery(item);
            scroll = (ScrolledPage<SalesPlanEsEntity>) elasticsearchTemplate
                    .startScroll(SCROLL_TIMEOUT, searchQuery, SalesPlanEsEntity.class);
            tmpList = new ArrayList<>();
            while (scroll.hasContent()) {
                tmpList.addAll(scroll.getContent());
                scroll = (ScrolledPage<SalesPlanEsEntity>) elasticsearchTemplate.continueScroll(
                        scroll.getScrollId(), SCROLL_TIMEOUT, SalesPlanEsEntity.class);
            }
            if (CollectionUtils.isEmpty(tmpList)) {
                continue;
            }
            //计算总量，根据总量和分量比值分摊确认量
            tmpTotal = tmpList.stream().map(subItem -> {
                if (subItem.getConfirm_l4() == null) {
                    return BigDecimal.ZERO;
                }
                return subItem.getConfirm_l4();
            }).reduce(BigDecimal::add).orElse(BigDecimal.ZERO);
            if (!SkuUnitTypeEnum.BASIS_UNIT.getUnitType().equals(unitType)) {
                tmpConfirmQty = item.getSupplyChainConfirmationQty().multiply(BigDecimal.valueOf(skuUnitDTOMap.get(item.getSkuCode() + unitType + SkuUnitTypeEnum.BASIS_UNIT.getUnitType()).getScale()));
            } else {
                tmpConfirmQty = item.getSupplyChainConfirmationQty();
            }
            if (BigDecimal.ZERO.compareTo(tmpTotal) == 0) {
                //不处理总分配量为0的数据
                continue;
            }
            for (SalesPlanEsEntity subItem : tmpList) {
                subItem.setRequire_confirm_qty(subItem.getConfirm_l4().multiply(tmpConfirmQty).divide(tmpTotal, 8, BigDecimal.ROUND_HALF_UP));
                queryList.add(new IndexQueryBuilder().withObject(subItem).withId(subItem.getId()).build());
            }
        }
        if (!CollectionUtils.isEmpty(queryList)) {
            List<List<IndexQuery>> lists = splitTo(queryList, 50000);
            for (List<IndexQuery> list : lists) {
                elasticsearchTemplate.bulkIndex(list);
                elasticsearchTemplate.refresh(SalesPlanEsEntity.class);
            }
        }
        //清空缓存
        commonService.clearCache(REDIS_CACHE_REQUIREMENT);
    }

    private SearchQuery getConfirmSearchQuery(RequirementConfirmationDTO item) {
        //渠道---区域---仓库---sku---日期
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        if (StringUtils.isEmpty(item.getWarehouseCode())) {
            throw new RomeException("999", "仓库编码为必传参数");
        }
        queryBuilder.filter(matchQuery(DELIVER_ID.getType(), item.getWarehouseCode()));
        if (StringUtils.isEmpty(item.getSkuCode())) {
            throw new RomeException("999", "商品编码为必传参数");
        }
        queryBuilder.filter(matchQuery(SKU_KEY.getType(), item.getSkuCode()));
        if (item.getPlanStartDate() == null) {
            throw new RomeException("999", "日期为必传参数");
        }
        queryBuilder.filter(matchQuery(FORMULATE_DATE.getType(), DateUtil.format(item.getPlanStartDate(), DatePattern.NORM_DATE_PATTERN)));
        return new NativeSearchQueryBuilder()
                .withQuery(queryBuilder)
                .withIndices(BigDataEsConstants.INDEX_NAME_PLAN_SALES_PLAN)
                .withPageable(PageRequest.of(0, 10))
                .build();
    }

    /**
     * 图表
     *
     * @param requirementPlanDTO
     * @return {@link EChartsDTO}
     **/
    @Override
    public EChartsDTO eChartsData(RequirementPlanDTO requirementPlanDTO) {
        EChartsDTO eChartsDTO = new EChartsDTO();
        //获取es查询条件,同时标记完搜索条件查询细粒度
        //获取es查询条件,同时标记完搜索条件查询细粒度
        SearchQuery searchQuery = this.getSearchQuery(requirementPlanDTO);
        //查询es
        Aggregations aggregations = elasticsearchTemplate.query(searchQuery, SearchResponse::getAggregations);
        //获取结果(已分页)
        List<RequirementPlanInfoDTO> result = this.dealResult(aggregations, requirementPlanDTO);
        if (CollectionUtils.isEmpty(result)) {
            return eChartsDTO;
        }
        int elementSize = requirementPlanDTO.getDateList().size();
        //设置预约在途采购量和未履约采购量
        this.setReservePurchaseQty(result, requirementPlanDTO, elementSize);
        //TODO 实际销量
        this.setActualQty(result, requirementPlanDTO, elementSize);
        //遍历
        RequirementPlanInfoDTO requirementPlanInfoDTO = new RequirementPlanInfoDTO();
        for (RequirementPlanInfoDTO item : result) {
            requirementPlanInfoDTO.setSalesPlanAmount(addList(requirementPlanInfoDTO.getSalesPlanAmount(), item.getSalesPlanAmount()));
            requirementPlanInfoDTO.setForecastPlanAmount(addList(requirementPlanInfoDTO.getForecastPlanAmount(), item.getForecastPlanAmount()));
            requirementPlanInfoDTO.setSalesPlanQty(addList(requirementPlanInfoDTO.getSalesPlanQty(), item.getSalesPlanQty()));
            requirementPlanInfoDTO.setForecastPlanQty(addList(requirementPlanInfoDTO.getForecastPlanQty(), item.getForecastPlanQty()));
            requirementPlanInfoDTO.setStockSafety(addList(requirementPlanInfoDTO.getStockSafety(), item.getStockSafety()));
            requirementPlanInfoDTO.setSupChainConfirmQty(addList(requirementPlanInfoDTO.getSupChainConfirmQty(), item.getSupChainConfirmQty()));
            requirementPlanInfoDTO.setSalePlanConfirmationQty(addList(requirementPlanInfoDTO.getSalePlanConfirmationQty(), item.getSalePlanConfirmationQty()));
            requirementPlanInfoDTO.setLastConfirmQty(addList(requirementPlanInfoDTO.getLastConfirmQty(), item.getLastConfirmQty()));
            requirementPlanInfoDTO.setLastSalePlanConfirmQty(addList(requirementPlanInfoDTO.getLastSalePlanConfirmQty(), item.getLastSalePlanConfirmQty()));
            requirementPlanInfoDTO.setReservePurchaseQty(addList(requirementPlanInfoDTO.getReservePurchaseQty(), item.getReservePurchaseQty()));
            requirementPlanInfoDTO.setActualSalesQty(addList(requirementPlanInfoDTO.getActualSalesQty(), item.getActualSalesQty()));
            requirementPlanInfoDTO.setNoFulfilPurchaseQty(addList(requirementPlanInfoDTO.getNoFulfilPurchaseQty(), item.getNoFulfilPurchaseQty()));
            requirementPlanInfoDTO.setRealTimeInventory(addList(requirementPlanInfoDTO.getRealTimeInventory(), item.getRealTimeInventory()));
        }
        Map<String, List<BigDecimal>> value = new HashMap<>();
        value.put(PLAN_SALE_AMOUNT.getType(), requirementPlanInfoDTO.getSalesPlanAmount());
        value.put(PREDICT_SALE_AMOUNT.getType(), requirementPlanInfoDTO.getForecastPlanAmount());
        value.put(PLAN_SALES.getType(), requirementPlanInfoDTO.getSalesPlanQty());
        value.put(PREDICT_SALES.getType(), requirementPlanInfoDTO.getForecastPlanQty());
        value.put(SAFETY_STOCK.getType(), requirementPlanInfoDTO.getStockSafety());
        value.put(REQUIRE_CONFIRM_QTY.getType(), requirementPlanInfoDTO.getSupChainConfirmQty());
        value.put(CONFIRM_L4.getType(), requirementPlanInfoDTO.getSalePlanConfirmationQty());
        value.put(LAST_REQUIRE_CONFIRM_QTY.getType(), requirementPlanInfoDTO.getLastConfirmQty());
        value.put(LAST_CONFIRM_L4.getType(), requirementPlanInfoDTO.getLastSalePlanConfirmQty());
        value.put(RESERVE_PURCHASE_QTY.getType(), requirementPlanInfoDTO.getReservePurchaseQty());
        value.put(ACTUAL_SALES.getType(), requirementPlanInfoDTO.getActualSalesQty());
        value.put(NO_FULFIL_PURCHASE_QTY.getType(), requirementPlanInfoDTO.getNoFulfilPurchaseQty());
        //设置标签
        eChartsDTO.setLabelData(this.getAllKeyLabels(RequirementPlanEnum.getLables()));
        eChartsDTO.setValue(value);
        //返回分页结果
        return eChartsDTO;
    }

    private List<BigDecimal> addList(@Nullable List<BigDecimal> source, List<BigDecimal> target) {
        if (source == null) {
            return target;
        }
        for (int i = 0; i < source.size(); i++) {
            source.set(i, source.get(i).add(target.get(i)));
        }
        return source;
    }

    private List<RequirementPlanInfoDTO> dealResult(Aggregations aggregations, RequirementPlanDTO requirementPlanDTO) {
        List<Long> dateListOfLong = requirementPlanDTO.getDateListOfLong();
        //总条数，返回总量
        List<RequirementPlanInfoDTO> result = new ArrayList<>();
        //每条数据
        RequirementPlanInfoDTO item;
        //临时数据，用来存储公共搜索数据
        RequirementPlanInfoDTO temp;
        //临时map
        Map<Long, BigDecimal> tempMap1;
        Map<Long, BigDecimal> tempMap2;
        Map<Long, BigDecimal> tempMap3;
        Map<Long, BigDecimal> tempMap4;
        Map<Long, BigDecimal> tempMap5;
        Map<Long, BigDecimal> planQtySumMap;
        Map<Long, BigDecimal> predictQtySumMap;
        Map<Long, BigDecimal> confirmQtySumMap;
        Map<Long, BigDecimal> preConfirmQtySumMap;
        //其它
        Map<String, Aggregations> areaAggregationsMap;
        Map<String, Aggregations> warehouseAggregationsMap;
        Map<String, Aggregations> skuAggregationsMap;
        Map<Long, Aggregations> dateAggregationsMap;
        Map<String, Aggregation> sumMap;
        Map<String, Aggregations> planTypeAggregationsMap;
        Map<String, Aggregation> planMap;
        InternalAvg priceAvg;
        InternalSum requireConfirmSum;
        InternalSum lastRequireConfirmSum;
        InternalAvg safetyStockAvg;
        InternalAvg inventoryAvg;
        InternalSum planQtySum;
        // 确认量
        InternalSum confirmQtySum;
        InternalSum otherConfirmSum;
        InternalSum preConfirmSum;
        InternalSum otherPreConfirmQtySum;
        String planType;
        Long tmpDate;
        // 销售计划量=所有除新品新店营销（已确定的量），按照渠道/商品/时间/区域汇总的计划量
        BigDecimal salesPlanSum;
        // 预测量=直营预测的预测量
        BigDecimal predictQty;
        // 确认量
        BigDecimal confirmQty;
        // 上次确认量
        BigDecimal preConfirmQty;
        //渠道所有桶
        Map<String, Aggregations> channelAggregationsMap = getSubAggregations(aggregations, GROUP_CHANNEL.getType());
        for (Map.Entry<String, Aggregations> channleEntry : channelAggregationsMap.entrySet()) {
            temp = new RequirementPlanInfoDTO();
            temp.setChannelCode(channleEntry.getKey());
            areaAggregationsMap = getSubAggregations(channleEntry.getValue(), GROUP_AREA.getType());
            for (Map.Entry<String, Aggregations> areaEntry : areaAggregationsMap.entrySet()) {
                this.setAreaCode(areaEntry.getKey(), temp, requirementPlanDTO);
                //仓库所有桶
                warehouseAggregationsMap = getSubAggregations(areaEntry.getValue(), GROUP_WAREHOUSE.getType());
                for (Map.Entry<String, Aggregations> warehouseEntry : warehouseAggregationsMap.entrySet()) {
                    temp.setWarehouseCode(warehouseEntry.getKey());
                    //sku所有桶
                    skuAggregationsMap = getSubAggregations(warehouseEntry.getValue(), GROUP_SKU.getType());
                    for (Map.Entry<String, Aggregations> skuEntry : skuAggregationsMap.entrySet()) {
                        temp.setSkuCode(skuEntry.getKey());
                        item = this.getRequirementPlanInfoDTO(temp);
                        //日期桶
                        dateAggregationsMap = getSubAggregations2(skuEntry.getValue(), GROUP_DATE.getType());
                        tempMap1 = new HashMap<>();
                        tempMap2 = new HashMap<>();
                        tempMap3 = new HashMap<>();
                        tempMap4 = new HashMap<>();
                        tempMap5 = new HashMap<>();
                        planQtySumMap = new HashMap<>();
                        predictQtySumMap = new HashMap<>();
                        confirmQtySumMap = new HashMap<>();
                        preConfirmQtySumMap = new HashMap<>();
                        for (Map.Entry<Long, Aggregations> dateEntry : dateAggregationsMap.entrySet()) {
                            tmpDate = dateEntry.getKey();
                            sumMap = dateEntry.getValue().asMap();
                            priceAvg = (InternalAvg) sumMap.get("group_price");
                            tempMap1.put(tmpDate, BigDecimal.valueOf("NaN".equals(String.valueOf(priceAvg.getValue())) ? 0 : priceAvg.getValue()));
                            requireConfirmSum = (InternalSum) sumMap.get(GROUP_REQUIRE_CONFIRM_QTY.getType());
                            tempMap2.put(tmpDate, BigDecimal.valueOf(requireConfirmSum.getValue()));
                            lastRequireConfirmSum = (InternalSum) sumMap.get(GROUP_LAST_REQUIRE_CONFIRM_QTY.getType());
                            tempMap3.put(tmpDate, BigDecimal.valueOf(lastRequireConfirmSum.getValue()));
                            safetyStockAvg = (InternalAvg) sumMap.get(GROUP_SAFETY_STOCK.getType());
                            tempMap4.put(tmpDate, BigDecimal.valueOf("NaN".equals(String.valueOf(safetyStockAvg.getValue())) ? 0 : safetyStockAvg.getValue()));
                            inventoryAvg = (InternalAvg) sumMap.get(GROUP_SALE_INVENTORY.getType());
                            tempMap5.put(tmpDate, BigDecimal.valueOf("NaN".equals(String.valueOf(inventoryAvg.getValue())) ? 0 : inventoryAvg.getValue()));
                            planTypeAggregationsMap = getSubAggregations(dateEntry.getValue(), GROUP_PLAN_TYPE.getType());
                            // 销售计划量=所有除新品新店营销（已确定的量），按照渠道/商品/时间/区域汇总的计划量
                            salesPlanSum = BigDecimal.ZERO;
                            // 预测量=直营预测的预测量
                            predictQty = BigDecimal.ZERO;
                            // 确认量
                            confirmQty = BigDecimal.ZERO;
                            // 上次确认量
                            preConfirmQty = BigDecimal.ZERO;
                            for (Map.Entry<String, Aggregations> planTypeEntry : planTypeAggregationsMap.entrySet()) {
                                planType = planTypeEntry.getKey();
                                planMap = planTypeEntry.getValue().asMap();
                                //计划量
                                planQtySum = (InternalSum) planMap.get("planQtySum");
                                // 确认量
                                confirmQtySum = (InternalSum) planMap.get("confirmQtySum");
                                otherConfirmSum = (InternalSum) planMap.get("otherConfirmSum");
                                // 上次确认量
                                preConfirmSum = (InternalSum) planMap.get("preConfirmSum");
                                otherPreConfirmQtySum = (InternalSum) planMap.get("otherPreConfirmQtySum");
                                if (!SalesOtherTypeEnum.PLAN_ONE.getType().equals(planType)
                                        && !SalesOtherTypeEnum.PLAN_SIX.getType().equals(planType)
                                        && !SalesOtherTypeEnum.PLAN_SEVEN.getType().equals(planType)) {
                                    salesPlanSum = salesPlanSum.add(internalSum2BigDecimal(planQtySum));
                                }
                                if ("17".equals(planType)) {
                                    predictQty = predictQty.add(internalSum2BigDecimal(planQtySum));
                                    confirmQty = confirmQty.add(internalSum2BigDecimal(confirmQtySum));
                                    preConfirmQty = preConfirmQty.add(internalSum2BigDecimal(preConfirmSum));
                                } else {
                                    confirmQty = confirmQty.add(internalSum2BigDecimal(otherConfirmSum));
                                    preConfirmQty = preConfirmQty.add(internalSum2BigDecimal(otherPreConfirmQtySum));
                                }
                            }
                            // 把指标按照时间放入map，然后重新构造成list，空日期的补0
                            planQtySumMap.put(tmpDate, salesPlanSum);
                            predictQtySumMap.put(tmpDate, predictQty);
                            confirmQtySumMap.put(tmpDate, confirmQty);
                            preConfirmQtySumMap.put(tmpDate, preConfirmQty);
                        }
                        //检验14周数据的合法性
                        this.checkValid(item, null, dateListOfLong, tempMap1, tempMap2, tempMap3, tempMap4, tempMap5, planQtySumMap, predictQtySumMap, confirmQtySumMap, preConfirmQtySumMap);
                        result.add(item);
                    }

                }
            }
        }
        return result;
    }

    private List<EChartsDTOLabelDataDTO> getAllKeyLabels(List<RequirementPlanEnum> lables) {
        List<EChartsDTOLabelDataDTO> list = new ArrayList<>();
        for (RequirementPlanEnum item : lables) {
            EChartsDTOLabelDataDTO eChartsDTOLabelDataDTO = new EChartsDTOLabelDataDTO();
            eChartsDTOLabelDataDTO.setKey(item.getType());
            eChartsDTOLabelDataDTO.setLabel(item.getDesc());
            list.add(eChartsDTOLabelDataDTO);
        }
        return list;
    }

    /**
     * 设置预约在途采购量
     *
     * @param pageResult
     * @param requirementPlanDTO
     * @param elementSize
     * @return void
     **/
    private void setReservePurchaseQty(List<RequirementPlanInfoDTO> pageResult, RequirementPlanDTO requirementPlanDTO, int elementSize) {
        if (CollectionUtils.isEmpty(pageResult)) {
            return;
        }
        PlanPoQueryDTO planPoQueryDTO = this.getPlanPoQueryDTO(pageResult, requirementPlanDTO);
        // 预约在途采购量
        List<PlanPoInfoDTO> appointments = purchaseFacade.listAppointmentQty(planPoQueryDTO);
        //未履约采购量
        List<PlanPoInfoDTO> noAgreement = purchaseFacade.listNoAgreementQty(planPoQueryDTO);
//        Map<String, BigDecimal> unitMap = this.getBaseSkuUnitRate(pageResult.stream().map(RequirementPlanInfoDTO::getSkuCode).distinct().collect(Collectors.toList()), SkuUnitTypeEnum.PURCHASE_UNIT.getUnitType());
        //根据仓库，skucode分组，获取每一组的 周起始时间——聚合值
        Map<String, Map<Date, BigDecimal>> result = new HashMap<>();
        Map<String, Map<Date, BigDecimal>> resultNoAgreement = new HashMap<>();
        if (CollectionUtils.isNotEmpty(appointments)) {
            result = appointments.stream().peek(item -> item.setCreateTime(DateUtil.beginOfWeek(item.getCreateTime()))).collect(groupingBy(item -> item.getWarehouseCode() + item.getSkuCode(), Collectors.collectingAndThen(Collectors.toList(), values -> values.stream().collect(groupingBy(PlanPoInfoDTO::getCreateTime, Collectors.collectingAndThen(Collectors.toList(), subValues -> subValues.stream().map(PlanPoInfoDTO::getAppointmentQty).reduce(BigDecimal.ZERO, BigDecimal::add)))))));
        }
        if (CollectionUtils.isNotEmpty(noAgreement)) {
            resultNoAgreement = noAgreement.stream().peek(item -> item.setCreateTime(DateUtil.beginOfWeek(item.getCreateTime()))).collect(groupingBy(item -> item.getWarehouseCode() + item.getSkuCode(), Collectors.collectingAndThen(Collectors.toList(), values -> values.stream().collect(groupingBy(PlanPoInfoDTO::getCreateTime, Collectors.collectingAndThen(Collectors.toList(), subValues -> subValues.stream().map(PlanPoInfoDTO::getNoFulfilPurchaseQty).reduce(BigDecimal.ZERO, BigDecimal::add)))))));
        }
        List<BigDecimal> blankList = this.getWeekBlankList(elementSize);
        Map<Date, BigDecimal> dateResult;
        Map<Date, BigDecimal> dateNoAgreement;
        List<BigDecimal> tmpList;
        List<Date> dateList = requirementPlanDTO.getDateList();
//        BigDecimal rate = null;
        BigDecimal tmpValue;
        for (RequirementPlanInfoDTO item : pageResult) {
//            rate = unitMap.get(item.getSkuCode());
//            if (rate == null) {
//                throw new RomeException(ResponseMsg.FAIL_6008.getCode(), "无法获取单位比例转换信息：" + "skuCode," + item.getSkuCode() + "; 单位类型" + SkuUnitTypeEnum.getNameByType(SkuUnitTypeEnum.PURCHASE_UNIT.getUnitType()));
//            }
            dateResult = result.get(item.getWarehouseCode() + item.getSkuCode());
            dateNoAgreement = resultNoAgreement.get(item.getWarehouseCode() + item.getSkuCode());
            if (dateResult != null) {
                tmpList = new ArrayList<>();
                for (Date date : dateList) {
                    tmpValue = dateResult.get(date);
                    if (tmpValue == null) {
                        tmpList.add(BigDecimal.ZERO);
                    } else {
                        tmpList.add(tmpValue);
                    }
                }
                item.setReservePurchaseQty(tmpList);
            } else {
                item.setReservePurchaseQty(blankList);
            }
            if (dateNoAgreement != null) {
                tmpList = new ArrayList<>();
                for (Date date : dateList) {
                    tmpValue = dateNoAgreement.get(date);
                    if (tmpValue == null) {
                        tmpList.add(BigDecimal.ZERO);
                    } else {
                        tmpList.add(tmpValue);
                    }
                }
                item.setNoFulfilPurchaseQty(tmpList);
            } else {
                item.setNoFulfilPurchaseQty(blankList);
            }
        }
    }

    /**
     * 获取其它单位运算为基础单位的比例
     *
     * @param skuCodes
     * @param unitType
     * @return {@link Map<BigDecimal>}
     **/
    private Map<String, BigDecimal> getBaseSkuUnitRate(List<String> skuCodes, Long unitType) {
        Map<String, BigDecimal> result;
        if (SkuUnitTypeEnum.BASIS_UNIT.getUnitType().equals(unitType)) {
            BigDecimal bigDecimal = new BigDecimal("1");
            result = skuCodes.stream().collect(Collectors.toMap(item -> item, item -> bigDecimal));
        } else {
            List<SkuUnitDTO> purchaseUnitRatio = itemCoreFacade.getConversionRatio(skuCodes, unitType);
            result = purchaseUnitRatio.stream().collect(Collectors.toMap(SkuUnitDTO::getSkuCode, item -> BigDecimal.valueOf(item.getScale())));
        }
        return result;
    }

    /**
     * 获取14周的空集合
     *
     * @param
     * @return {@link List<BigDecimal>}
     **/
    private List<BigDecimal> getWeekBlankList(int elementSize) {
        List<BigDecimal> blankList = new ArrayList<>(elementSize);
        for (int i = 0; i < elementSize; i++) {
            blankList.add(BigDecimal.ZERO);
        }
        return blankList;
    }

    private PlanPoQueryDTO getPlanPoQueryDTO(List<RequirementPlanInfoDTO> pageResult, RequirementPlanDTO requirementPlanDTO) {
        PlanPoQueryDTO planPoQueryDTO = new PlanPoQueryDTO();
        planPoQueryDTO.setStartTime(requirementPlanDTO.getStartDate());
        planPoQueryDTO.setEndTime(DateUtil.endOfDay(requirementPlanDTO.getEndDate()));
        planPoQueryDTO.setSkuCodes(pageResult.stream().map(RequirementPlanInfoDTO::getSkuCode).distinct().collect(Collectors.toList()));
        planPoQueryDTO.setWarehouseCodes(pageResult.stream().map(RequirementPlanInfoDTO::getWarehouseCode).distinct().collect(Collectors.toList()));
        return planPoQueryDTO;
    }

    /**
     * 设置供应链确认量
     *
     * @param pageResult
     * @param requirementPlanDTO
     * @return void
     **/
    private void setSupplyChainQty(List<RequirementPlanInfoDTO> pageResult, RequirementPlanDTO requirementPlanDTO) {
        //根据批量条件：收货仓库，skucode，周起始日期     查找实际需要数据
        List<RequirementConfirmationDO> requirementConfirmationDOS;
        if (!CollectionUtils.isEmpty(pageResult)) {
            requirementConfirmationDOS = requirementConfirmationRepository.selectSupplyChainQty(pageResult, requirementPlanDTO.getStartDate(), DateUtil.parse(requirementPlanDTO.getLastOfStartDateStr()));
        } else {
            return;
        }
        //按照仓库和sku分组，按照date从小到大排序
        if (!CollectionUtils.isEmpty(requirementConfirmationDOS)) {
            RequirementConfirmationDO requirementConfirmationDO;
            List<Date> dateList = requirementPlanDTO.getDateList();
            Map<String, Map<Date, RequirementConfirmationDO>> resulMap = requirementConfirmationDOS.stream().collect(groupingBy(item -> item.getWarehouseCode() + item.getSkuCode(), Collectors.collectingAndThen(Collectors.toList(), values -> values.stream().collect(Collectors.toMap(item -> item.getPlanStartDate(), item -> item)))));
            for (RequirementPlanInfoDTO item : pageResult) {
                Map<Date, RequirementConfirmationDO> itemMap = resulMap.get(item.getWarehouseCode() + item.getSkuCode());
                if (itemMap == null) {
                    throw new RomeException("999", "mysql数据库中缺少供应链确认量数据：商品编码," + item.getSkuCode() + " 仓库编码," + item.getWarehouseCode());
                }
                List<BigDecimal> supplyChainConfirmationQtys = new ArrayList<>();
                List<BigDecimal> lastConfirmQtys = new ArrayList<>();
                for (Date date : dateList) {
                    requirementConfirmationDO = itemMap.get(date);
                    if (requirementConfirmationDO != null) {
                        supplyChainConfirmationQtys.add(requirementConfirmationDO.getSupplyChainConfirmationQty());
                        lastConfirmQtys.add(requirementConfirmationDO.getLastConfirmQty());
                    } else {
                        supplyChainConfirmationQtys.add(null);
                        lastConfirmQtys.add(null);
                    }
                }
                item.setSupChainConfirmQty(supplyChainConfirmationQtys);
                item.setLastConfirmQty(lastConfirmQtys);
            }
        } else {
            throw new RomeException("999", "mysql数据库中缺少该页面所有供应链确认量数据");
        }
    }

    /**
     * 处理前端名称的信息展示--品类
     *
     * @param pageResult
     * @param requirementPlanDTO
     * @return void
     **/
    private void setGeneralInfo(List<RequirementPlanInfoDTO> pageResult, RequirementPlanDTO requirementPlanDTO) {
        if (CollectionUtils.isEmpty(pageResult)) {
            return;
        }
        //渠道查询
        List<ChannelDTO> channels = baseDataFacade.getChannelByLevel(1);
        Map<String, String> channelMap = channels.stream().collect(Collectors.toMap(ChannelDTO::getChannel, ChannelDTO::getChannelName));
        //品类查询
        Map<String, BaseSkuInfoDTO> baseSkuInfoDTOMap = commonService.getCategoryInfoBySkuCodes(pageResult.stream().map(RequirementPlanInfoDTO::getSkuCode).distinct().collect(Collectors.toList()));
        //区域查询
        Map<String, String> areaMap = new HashMap<>(1);
        if (requirementPlanDTO.getExistStore()) {
            List<StoreDTO> storeDTOS = baseDataFacade.selectStoreListByCodes(pageResult.stream().map(RequirementPlanInfoDTO::getStoreCode).distinct().collect(Collectors.toList()));
            areaMap = storeDTOS.stream().collect(Collectors.toMap(StoreDTO::getCode, item -> item.getProvince() + "/" + item.getCity() + "/" + item.getCounty() + "/" + item.getName()));
        }
        if (requirementPlanDTO.getExistPro() || requirementPlanDTO.getExistCity() || requirementPlanDTO.getExistCount() || requirementPlanDTO.getExistStore()) {
            List<String> areaList = null;
            if (requirementPlanDTO.getExistPro()) {
                areaList = pageResult.stream().map(RequirementPlanInfoDTO::getProvinceCode).distinct().collect(Collectors.toList());
            }
            if (requirementPlanDTO.getExistCity()) {
                areaList = pageResult.stream().map(RequirementPlanInfoDTO::getCityCode).distinct().collect(Collectors.toList());
            }
            if (requirementPlanDTO.getExistCount()) {
                areaList = pageResult.stream().map(RequirementPlanInfoDTO::getCountyCode).distinct().collect(Collectors.toList());
            }
            List<AreaLevelDTO> areaLevelDTOS = baseDataFacade.listRelationByArea(areaList);
            areaMap = areaLevelDTOS.stream().peek(item -> item.setNameFullPath(item.getNameFullPath().replace("中国-", "").replace("-", "/"))).collect(Collectors.toMap(AreaLevelDTO::getCode, AreaLevelDTO::getNameFullPath));
        }
        List<StoreDTO> storeDTOS = stockCoreFacade.queryFactoryByRwType(16);
        Map<String, String> storeMap = storeDTOS.stream().collect(Collectors.toMap(StoreDTO::getCode, StoreDTO::getName));
        this.setGeneralInfoDetail(pageResult, baseSkuInfoDTOMap, areaMap, requirementPlanDTO, storeMap, channelMap);
    }

    /**
     * 设置品类通用信息
     *
     * @param pageResult
     * @return void
     **/
    private void setGeneralInfoDetail(List<RequirementPlanInfoDTO> pageResult, Map<String, BaseSkuInfoDTO> baseSkuInfoDTOMap, Map<String, String> areaMap, RequirementPlanDTO requirementPlanDTO, Map<String, String> storeMap, Map<String, String> channelMap) {
        //设置大中小品类
        String skuCode;
        BaseSkuInfoDTO baseSkuInfoDTO;
        for (RequirementPlanInfoDTO requirementPlanInfoDTO : pageResult) {
            requirementPlanInfoDTO.setChannel(channelMap.get(requirementPlanInfoDTO.getChannelCode()));
            skuCode = requirementPlanInfoDTO.getSkuCode();
            baseSkuInfoDTO = baseSkuInfoDTOMap.get(skuCode);
            requirementPlanInfoDTO.setSkuName(baseSkuInfoDTO.getSkuName());
            requirementPlanInfoDTO.setCategory(baseSkuInfoDTO.getCategory());
            requirementPlanInfoDTO.setPriCategoryCode(baseSkuInfoDTO.getPriCategoryCode());
            requirementPlanInfoDTO.setSecCategoryCode(baseSkuInfoDTO.getSecCategoryCode());
            requirementPlanInfoDTO.setTerCategoryCode(baseSkuInfoDTO.getTerCategoryCode());
            if (requirementPlanDTO.getExistPro()) {
                requirementPlanInfoDTO.setArea(areaMap.get(requirementPlanInfoDTO.getProvinceCode()));
            }
            if (requirementPlanDTO.getExistCity()) {
                requirementPlanInfoDTO.setArea(areaMap.get(requirementPlanInfoDTO.getCityCode()));
            }
            if (requirementPlanDTO.getExistCount()) {
                requirementPlanInfoDTO.setArea(areaMap.get(requirementPlanInfoDTO.getCountyCode()));
            }
            if (requirementPlanDTO.getExistStore()) {
                requirementPlanInfoDTO.setArea(areaMap.get(requirementPlanInfoDTO.getStoreCode()));
            }
            requirementPlanInfoDTO.setWarehouseName(storeMap.get(requirementPlanInfoDTO.getWarehouseCode()));
        }
    }

    /**
     * 处理es查询结果，获取页面展示结构数据
     *
     * @param aggregations
     * @param requirementPlanDTO
     * @param PageInfo
     * @return {@link List<RequirementPlanInfoDTO>}
     **/
    private List<RequirementPlanInfoDTO> dealResultPage(Aggregations aggregations, RequirementPlanDTO requirementPlanDTO, PageInfo<RequirementPlanInfoDTO> PageInfo) {
        int startIndex = (requirementPlanDTO.getPageNum() - 1) * requirementPlanDTO.getPageSize();
        int endIndex = requirementPlanDTO.getPageNum() * requirementPlanDTO.getPageSize() - 1;
        int totalNum = 0;
        List<Long> dateListOfLong = requirementPlanDTO.getDateListOfLong();
        Long thisDayOfLong = requirementPlanDTO.getThisDayOfLong();
        //总条数，返回总量
        List<RequirementPlanInfoDTO> result = new ArrayList<>();
        //每条数据
        RequirementPlanInfoDTO item;
        //临时数据，用来存储公共搜索数据
        RequirementPlanInfoDTO temp;
        //临时map
        Map<Long, BigDecimal> tempMap1;
        Map<Long, BigDecimal> tempMap2;
        Map<Long, BigDecimal> tempMap3;
        Map<Long, BigDecimal> tempMap4;
        Map<Long, BigDecimal> tempMap5;
        Map<Long, BigDecimal> planQtySumMap;
        Map<Long, BigDecimal> predictQtySumMap;
        Map<Long, BigDecimal> confirmQtySumMap;
        Map<Long, BigDecimal> preConfirmQtySumMap;
        //其它
        Map<String, Aggregations> areaAggregationsMap;
        Map<String, Aggregations> warehouseAggregationsMap;
        Map<String, Aggregations> skuAggregationsMap;
        Map<Long, Aggregations> dateAggregationsMap;
        Map<String, Aggregation> sumMap;
        Map<String, Aggregations> planTypeAggregationsMap;
        Map<String, Aggregation> planMap;
        InternalAvg priceAvg;
        InternalSum requireConfirmSum;
        InternalSum lastRequireConfirmSum;
        InternalAvg safetyStockAvg;
        InternalAvg inventoryAvg;
        InternalSum planQtySum;
        // 确认量
        InternalSum confirmQtySum;
        InternalSum otherConfirmSum;
        InternalSum preConfirmSum;
        InternalSum otherPreConfirmQtySum;
        String planType;
        Long tmpDate;
        // 销售计划量=所有除新品新店营销（已确定的量），按照渠道/商品/时间/区域汇总的计划量
        BigDecimal salesPlanSum;
        // 预测量=直营预测的预测量
        BigDecimal predictQty;
        // 确认量
        BigDecimal confirmQty;
        // 上次确认量
        BigDecimal preConfirmQty;
        //渠道所有桶
        Map<String, Aggregations> channelAggregationsMap = getSubAggregations(aggregations, GROUP_CHANNEL.getType());
        for (Map.Entry<String, Aggregations> channleEntry : channelAggregationsMap.entrySet()) {
            temp = new RequirementPlanInfoDTO();
            temp.setChannelCode(channleEntry.getKey());
            areaAggregationsMap = getSubAggregations(channleEntry.getValue(), GROUP_AREA.getType());
            for (Map.Entry<String, Aggregations> areaEntry : areaAggregationsMap.entrySet()) {
                this.setAreaCode(areaEntry.getKey(), temp, requirementPlanDTO);
                //仓库所有桶
                warehouseAggregationsMap = getSubAggregations(areaEntry.getValue(), GROUP_WAREHOUSE.getType());
                for (Map.Entry<String, Aggregations> warehouseEntry : warehouseAggregationsMap.entrySet()) {
                    temp.setWarehouseCode(warehouseEntry.getKey());
                    //sku所有桶
                    skuAggregationsMap = getSubAggregations(warehouseEntry.getValue(), GROUP_SKU.getType());
                    for (Map.Entry<String, Aggregations> skuEntry : skuAggregationsMap.entrySet()) {
                        if (!(totalNum >= startIndex && totalNum <= endIndex)) {
                            totalNum++;
                            continue;
                        }
                        totalNum++;
                        temp.setSkuCode(skuEntry.getKey());
                        item = this.getRequirementPlanInfoDTO(temp);
                        //日期桶
                        dateAggregationsMap = getSubAggregations2(skuEntry.getValue(), GROUP_DATE.getType());
                        tempMap1 = new HashMap<>();
                        tempMap2 = new HashMap<>();
                        tempMap3 = new HashMap<>();
                        tempMap4 = new HashMap<>();
                        tempMap5 = new HashMap<>();
                        planQtySumMap = new HashMap<>();
                        predictQtySumMap = new HashMap<>();
                        confirmQtySumMap = new HashMap<>();
                        preConfirmQtySumMap = new HashMap<>();
                        for (Map.Entry<Long, Aggregations> dateEntry : dateAggregationsMap.entrySet()) {
                            tmpDate = dateEntry.getKey();
                            sumMap = dateEntry.getValue().asMap();
                            priceAvg = (InternalAvg) sumMap.get("group_price");
                            tempMap1.put(tmpDate, BigDecimal.valueOf("NaN".equals(String.valueOf(priceAvg.getValue())) ? 0 : priceAvg.getValue()));
                            requireConfirmSum = (InternalSum) sumMap.get(GROUP_REQUIRE_CONFIRM_QTY.getType());
                            tempMap2.put(tmpDate, BigDecimal.valueOf(requireConfirmSum.getValue()));
                            lastRequireConfirmSum = (InternalSum) sumMap.get(GROUP_LAST_REQUIRE_CONFIRM_QTY.getType());
                            tempMap3.put(tmpDate, BigDecimal.valueOf(lastRequireConfirmSum.getValue()));
                            safetyStockAvg = (InternalAvg) sumMap.get(GROUP_SAFETY_STOCK.getType());
                            tempMap4.put(tmpDate, BigDecimal.valueOf("NaN".equals(String.valueOf(safetyStockAvg.getValue())) ? 0 : safetyStockAvg.getValue()));
                            inventoryAvg = (InternalAvg) sumMap.get(GROUP_SALE_INVENTORY.getType());
                            tempMap5.put(tmpDate, BigDecimal.valueOf("NaN".equals(String.valueOf(inventoryAvg.getValue())) ? 0 : inventoryAvg.getValue()));
                            planTypeAggregationsMap = getSubAggregations(dateEntry.getValue(), GROUP_PLAN_TYPE.getType());
                            // 销售计划量=所有除新品新店营销（已确定的量），按照渠道/商品/时间/区域汇总的计划量
                            salesPlanSum = BigDecimal.ZERO;
                            // 预测量=直营预测的预测量
                            predictQty = BigDecimal.ZERO;
                            // 确认量
                            confirmQty = BigDecimal.ZERO;
                            // 上次确认量
                            preConfirmQty = BigDecimal.ZERO;
                            for (Map.Entry<String, Aggregations> planTypeEntry : planTypeAggregationsMap.entrySet()) {
                                planType = planTypeEntry.getKey();
                                planMap = planTypeEntry.getValue().asMap();
                                //计划量
                                planQtySum = (InternalSum) planMap.get("planQtySum");
                                // 确认量
                                confirmQtySum = (InternalSum) planMap.get("confirmQtySum");
                                otherConfirmSum = (InternalSum) planMap.get("otherConfirmSum");
                                // 上次确认量
                                preConfirmSum = (InternalSum) planMap.get("preConfirmSum");
                                otherPreConfirmQtySum = (InternalSum) planMap.get("otherPreConfirmQtySum");
                                if (!SalesOtherTypeEnum.PLAN_ONE.getType().equals(planType)
                                        && !SalesOtherTypeEnum.PLAN_SIX.getType().equals(planType)
                                        && !SalesOtherTypeEnum.PLAN_SEVEN.getType().equals(planType)) {
                                    salesPlanSum = salesPlanSum.add(internalSum2BigDecimal(planQtySum));
                                }
                                if ("17".equals(planType)) {
                                    predictQty = predictQty.add(internalSum2BigDecimal(planQtySum));
                                    confirmQty = confirmQty.add(internalSum2BigDecimal(confirmQtySum));
                                    preConfirmQty = preConfirmQty.add(internalSum2BigDecimal(preConfirmSum));
                                } else {
                                    confirmQty = confirmQty.add(internalSum2BigDecimal(otherConfirmSum));
                                    preConfirmQty = preConfirmQty.add(internalSum2BigDecimal(otherPreConfirmQtySum));
                                }
                            }
                            // 把指标按照时间放入map，然后重新构造成list，空日期的补0
                            planQtySumMap.put(tmpDate, salesPlanSum);
                            predictQtySumMap.put(tmpDate, predictQty);
                            confirmQtySumMap.put(tmpDate, confirmQty);
                            preConfirmQtySumMap.put(tmpDate, preConfirmQty);
                        }
                        //检验14周数据的合法性
                        this.checkValid(item, thisDayOfLong, dateListOfLong, tempMap1, tempMap2, tempMap3, tempMap4, tempMap5, planQtySumMap, predictQtySumMap, confirmQtySumMap, preConfirmQtySumMap);
                        result.add(item);
                    }

                }
            }
        }
        PageInfo.setTotal(totalNum);
        return result;
    }

    private BigDecimal internalSum2BigDecimal(InternalSum sum) {
        if (sum == null) {
            return BigDecimal.ZERO;
        }
        return BigDecimal.valueOf(sum.getValue());
    }
//    private Map<String, List<BigDecimal>> dealEChartResult(Aggregations aggregations, RequirementPlanDTO requirementPlanDTO) {
//        List<Long> dateListOfLong = requirementPlanDTO.getDateListOfLong();
//        Map<Long, BigDecimal> tempMap2 = new HashMap<>();
//        Map<String, Aggregation> sumMap;
//        InternalSum requirementNumsSum;
//        //日期桶
//        Map<Long, Aggregations> dateAggregationsMap = getSubAggregations2(aggregations, GROUP_DATE.getType());
//        for (Map.Entry<Long, Aggregations> dateEntry : dateAggregationsMap.entrySet()) {
//            sumMap = dateEntry.getValue().asMap();
//            requirementNumsSum = (InternalSum) sumMap.get(GROUP_REQUIREMENT_NUMS.getType());
//            tempMap2.put(dateEntry.getKey(), BigDecimal.valueOf(requirementNumsSum.getValue()));
//        }
//        List<BigDecimal> forecastPlanQty = new ArrayList<>();
//        dateListOfLong.forEach(item -> {
//            forecastPlanQty.add(tempMap2.get(item));
//        });
//        Map<String, List<BigDecimal>> result = new HashMap<>();
//        result.put(FORECAST_PLAN_QTY.getType(), forecastPlanQty);
//        return result;
//    }

    /**
     * 检验14周数据的合法性
     *
     * @param requirementPlanInfoDTO
     * @return void
     **/
    private void checkValid(RequirementPlanInfoDTO requirementPlanInfoDTO, Long thisDayOfLong, List<Long> dateListOfLong, Map<Long, BigDecimal> tempMap1, Map<Long, BigDecimal> tempMap2, Map<Long, BigDecimal> tempMap3, Map<Long, BigDecimal> tempMap4, Map<Long, BigDecimal> tempMap5, Map<Long, BigDecimal> planQtySumMap, Map<Long, BigDecimal> predictQtySumMap, Map<Long, BigDecimal> confirmQtySumMap, Map<Long, BigDecimal> preConfirmQtySumMap) {
        List<BigDecimal> supChainConfirmQty = new ArrayList<>();
        List<BigDecimal> lastConfirmQty = new ArrayList<>();
        List<BigDecimal> stockSafety = new ArrayList<>();
        List<BigDecimal> inventory = new ArrayList<>();
        List<BigDecimal> planQty = new ArrayList<>();
        List<BigDecimal> planAmount = new ArrayList<>();
        List<BigDecimal> predictQty = new ArrayList<>();
        List<BigDecimal> predictAmount = new ArrayList<>();
        List<BigDecimal> confirmQty = new ArrayList<>();
        List<BigDecimal> preConfirmQty = new ArrayList<>();
        List<Integer> status = new ArrayList<>();
        BigDecimal tmpPlan;
        BigDecimal tmpPredict;
        BigDecimal tmpPrice;
        for (Long itemDate : dateListOfLong) {
            if (thisDayOfLong != null && thisDayOfLong <= itemDate) {
                status.add(1);
            } else {
                status.add(0);
            }
            supChainConfirmQty.add(tempMap2.get(itemDate) == null ? BigDecimal.ZERO : tempMap2.get(itemDate));
            lastConfirmQty.add(tempMap3.get(itemDate) == null ? BigDecimal.ZERO : tempMap3.get(itemDate));
            stockSafety.add(tempMap4.get(itemDate) == null ? BigDecimal.ZERO : tempMap4.get(itemDate));
            inventory.add(tempMap5.get(itemDate) == null ? BigDecimal.ZERO : tempMap5.get(itemDate));
            planQty.add(planQtySumMap.get(itemDate) == null ? BigDecimal.ZERO : planQtySumMap.get(itemDate));
            predictQty.add(predictQtySumMap.get(itemDate) == null ? BigDecimal.ZERO : predictQtySumMap.get(itemDate));
            confirmQty.add(confirmQtySumMap.get(itemDate) == null ? BigDecimal.ZERO : confirmQtySumMap.get(itemDate));
            preConfirmQty.add(preConfirmQtySumMap.get(itemDate) == null ? BigDecimal.ZERO : preConfirmQtySumMap.get(itemDate));
            tmpPlan = planQtySumMap.get(itemDate);
            tmpPrice = tempMap1.get(itemDate);
            tmpPredict = predictQtySumMap.get(itemDate);
            if (tmpPrice != null) {
                if (tmpPlan != null) {
                    planAmount.add(tmpPlan.multiply(tmpPrice));
                } else {
                    planAmount.add(BigDecimal.ZERO);
                }
                if (tmpPredict != null) {
                    predictAmount.add(tmpPredict.multiply(tmpPrice));
                } else {
                    predictAmount.add(BigDecimal.ZERO);
                }
            } else {
                planAmount.add(BigDecimal.ZERO);
                predictAmount.add(BigDecimal.ZERO);
            }
        }
        if (CollectionUtils.isNotEmpty(status)) {
            requirementPlanInfoDTO.setStatus(status);
        }
        requirementPlanInfoDTO.setSupChainConfirmQty(supChainConfirmQty);
        requirementPlanInfoDTO.setLastConfirmQty(lastConfirmQty);
        requirementPlanInfoDTO.setStockSafety(stockSafety);
        requirementPlanInfoDTO.setRealTimeInventory(inventory);
        requirementPlanInfoDTO.setSalesPlanQty(planQty);
        requirementPlanInfoDTO.setForecastPlanQty(predictQty);
        requirementPlanInfoDTO.setSalePlanConfirmationQty(confirmQty);
        requirementPlanInfoDTO.setLastSalePlanConfirmQty(preConfirmQty);
        requirementPlanInfoDTO.setSalesPlanAmount(planAmount);
        requirementPlanInfoDTO.setForecastPlanAmount(predictAmount);
    }

    /**
     * 设置必要属性
     *
     * @param temp
     * @return {@link RequirementPlanInfoDTO}
     **/
    private RequirementPlanInfoDTO getRequirementPlanInfoDTO(RequirementPlanInfoDTO temp) {
        RequirementPlanInfoDTO requirementPlanInfoDTO = new RequirementPlanInfoDTO();
        requirementPlanInfoDTO.setChannelCode(temp.getChannelCode());
        requirementPlanInfoDTO.setProvinceCode(temp.getProvinceCode());
        requirementPlanInfoDTO.setCityCode(temp.getCityCode());
        requirementPlanInfoDTO.setCountyCode(temp.getCountyCode());
        requirementPlanInfoDTO.setStoreCode(temp.getStoreCode());
        requirementPlanInfoDTO.setWarehouseCode(temp.getWarehouseCode());
        requirementPlanInfoDTO.setSkuCode(temp.getSkuCode());
//        requirementPlanInfoDTO.setSalesPlanAmountLabel(RequirementPlanTargetEnum.SALES_PLAN_AMOUNT.getDesc());
//        requirementPlanInfoDTO.setForecastPlanAmountLabel(RequirementPlanTargetEnum.FORECAST_PLAN_AMOUNT.getDesc());
        requirementPlanInfoDTO.setForecastPlanQtyLabel(RequirementPlanTargetEnum.FORECAST_PLAN_QTY.getDesc());
        requirementPlanInfoDTO.setSalesPlanQtyLabel(RequirementPlanTargetEnum.SALES_PLAN_QTY.getDesc());
        requirementPlanInfoDTO.setStockSafetyLabel(RequirementPlanTargetEnum.SAFETY_STOCK_QTY.getDesc());
        requirementPlanInfoDTO.setSupChainConfirmQtyLabel(RequirementPlanTargetEnum.SUPPLY_CHAIN_CONFIRMATION_QTY.getDesc());
        requirementPlanInfoDTO.setSalePlanConfirmationQtyLabel(RequirementPlanTargetEnum.SALE_PLAN_CONFIRMATION_QTY.getDesc());
        requirementPlanInfoDTO.setLastConfirmQtyLabel(RequirementPlanTargetEnum.LAST_CONFIRM_QTY.getDesc());
        requirementPlanInfoDTO.setLastSalePlanConfirmQtyLabel(RequirementPlanTargetEnum.LAST_SALE_PLAN_CONFIRM_QTY.getDesc());
        requirementPlanInfoDTO.setReservePurchaseQtyLabel(RequirementPlanTargetEnum.RESERVE_PURCHASE_QTY.getDesc());
        requirementPlanInfoDTO.setActualSalesQtyLabel(RequirementPlanTargetEnum.ACTUAL_SALES_QTY.getDesc());
        requirementPlanInfoDTO.setNoFulfilPurchaseQtyLabel(RequirementPlanTargetEnum.NO_FULFIL_PURCHASE_QTY.getDesc());
        requirementPlanInfoDTO.setRealTimeInventoryLabel(RequirementPlanTargetEnum.REAL_TIME_INVENTORY.getDesc());
        return requirementPlanInfoDTO;
    }

    private void setAreaCode(String key, RequirementPlanInfoDTO temp, RequirementPlanDTO requirementPlanDTO) {
        if (requirementPlanDTO.getExistPro()) {
            temp.setProvinceCode(key);
        }
        if (requirementPlanDTO.getExistCity()) {
            temp.setCityCode(key);
        }
        if (requirementPlanDTO.getExistCount()) {
            temp.setCountyCode(key);
        }
        if (requirementPlanDTO.getExistStore()) {
            temp.setStoreCode(key);
        }
    }

    /**
     * 获取下级聚合数据
     *
     * @param aggregations
     * @param subKey
     * @return 返回map，key是下级指标，值是聚合Aggregations对象
     */
    private Map<String, Aggregations> getSubAggregations(Aggregations aggregations, String subKey) {
        Map<String, Aggregation> aggregationMap = aggregations.asMap();
        StringTerms stringTerms = (StringTerms) aggregationMap.get(subKey);
        List<StringTerms.Bucket> buckets = stringTerms.getBuckets();
        return buckets.stream().collect(Collectors.toMap(bucket -> (String) bucket.getKey(), InternalTerms.Bucket::getAggregations));
    }

    private Map<Long, Aggregations> getSubAggregations2(Aggregations aggregations, String subKey) {
        Map<String, Aggregation> aggregationMap = aggregations.asMap();
        LongTerms longTerms = (LongTerms) aggregationMap.get(subKey);
        List<LongTerms.Bucket> buckets = longTerms.getBuckets();
        return buckets.stream().collect(Collectors.toMap(bucket -> (Long) bucket.getKey(), InternalTerms.Bucket::getAggregations));
    }

    /**
     * 获取es查询条件
     *
     * @param requirementPlanDTO
     * @return {@link SearchQuery}
     **/
    private SearchQuery getSearchQuery(RequirementPlanDTO requirementPlanDTO) {
        //获取es过滤条件
        BoolQueryBuilder queryBuilder = this.getBoolQueryBuilder(requirementPlanDTO);
        //获取es分组条件
        AbstractAggregationBuilder<TermsAggregationBuilder> aggregationBuilder = this.getAggregationBuilder(requirementPlanDTO);
        return new NativeSearchQueryBuilder()
                .withQuery(queryBuilder)
                .withIndices(BigDataEsConstants.INDEX_NAME_PLAN_SALES_PLAN)
                .addAggregation(aggregationBuilder)
                .build();
    }

    /**
     * 获取es分组条件
     *
     * @param requirementPlanDTO
     * @return {@link AbstractAggregationBuilder}
     **/
    private AbstractAggregationBuilder<TermsAggregationBuilder> getAggregationBuilder(RequirementPlanDTO requirementPlanDTO) {
        //渠道分组
        TermsAggregationBuilder termChannel = AggregationBuilders.terms(GROUP_CHANNEL.getType()).field(CHANNEL.getType()).size(Integer.MAX_VALUE).shardSize(Integer.MAX_VALUE);
        //区域分组
        TermsAggregationBuilder termArea = null;
        boolean flag = true;
        if (requirementPlanDTO.getExistCity()) {
            termArea = AggregationBuilders.terms(GROUP_AREA.getType())
                    .field(CITY.getType()).size(Integer.MAX_VALUE).shardSize(Integer.MAX_VALUE);
            flag = false;
        }
        if (requirementPlanDTO.getExistCount()) {
            termArea = AggregationBuilders.terms(GROUP_AREA.getType())
                    .field(DISTRICT.getType()).size(Integer.MAX_VALUE).shardSize(Integer.MAX_VALUE);
            flag = false;
        }
        if (requirementPlanDTO.getExistStore()) {
            termArea = AggregationBuilders.terms(GROUP_AREA.getType())
                    .field(NODE_ID.getType()).size(Integer.MAX_VALUE).shardSize(Integer.MAX_VALUE);
            flag = false;
        }
        if (flag) {
            requirementPlanDTO.setExistPro(true);
            termArea = AggregationBuilders.terms(GROUP_AREA.getType())
                    .field(PROVINCE.getType()).size(Integer.MAX_VALUE).shardSize(Integer.MAX_VALUE);
        }
        termChannel.subAggregation(termArea);
        //仓库分组(必然分组)
        TermsAggregationBuilder termWarehouse = AggregationBuilders.terms(GROUP_WAREHOUSE.getType())
                .field(DELIVER_ID.getType()).size(Integer.MAX_VALUE).shardSize(Integer.MAX_VALUE);
        termArea.subAggregation(termWarehouse);
        //sku分组（必然分组）
        TermsAggregationBuilder termSku = AggregationBuilders.terms(GROUP_SKU.getType())
                .field(SKU_KEY.getType()).size(Integer.MAX_VALUE).shardSize(Integer.MAX_VALUE);
        termWarehouse.subAggregation(termSku);
        //计划开始日期分组（必然分组）
        TermsAggregationBuilder termDate = AggregationBuilders.terms(GROUP_DATE.getType())
                .field(FORMULATE_DATE.getType()).size(Integer.MAX_VALUE).shardSize(Integer.MAX_VALUE);
        termSku.subAggregation(termDate);
        //聚合预测计划量,本次供应链确认量，上次供应链确认量,安全库存量，期末库存
        termDate.subAggregation(AggregationBuilders.sum(GROUP_REQUIRE_CONFIRM_QTY.getType()).field(REQUIRE_CONFIRM_QTY.getType()));
        termDate.subAggregation(AggregationBuilders.sum(GROUP_LAST_REQUIRE_CONFIRM_QTY.getType()).field(LAST_REQUIRE_CONFIRM_QTY.getType()));
        termDate.subAggregation(AggregationBuilders.avg(GROUP_SAFETY_STOCK.getType()).field(SAFETY_STOCK.getType()));
        termDate.subAggregation(AggregationBuilders.avg("group_price").field("averagePrice"));
        TermsAggregationBuilder termPlanType = AggregationBuilders.terms(GROUP_PLAN_TYPE.getType())
                .field(PLAN_TYPE.getType()).size(Integer.MAX_VALUE).shardSize(Integer.MAX_VALUE);
        termPlanType.subAggregation(AggregationBuilders.sum("planQtySum").field(PREDICT_SALES.getType()))
                // 直营预测计划类型的确认量，取值的字段通过等级计算
                .subAggregation(AggregationBuilders.sum("confirmQtySum").field("last_confirm_l" + 4))
                // 非直营计划类型的确认量
                .subAggregation(AggregationBuilders.sum("otherConfirmSum").field("last_confirm_l4"))
                // 直营预测计划类型的上次确认量（字段根据用户的等级来定，2级、3级、4级）
                .subAggregation(AggregationBuilders.sum("preConfirmSum").field("last_confirm_l" + 4))
                // 非直营预测的上次确认量
                .subAggregation(AggregationBuilders.sum("otherPreConfirmQtySum").field("last_confirm_l4"));
        termDate.subAggregation(termPlanType);
        return termChannel;
    }

    /**
     * 获取es分组条件
     *
     * @param requirementPlanDTO
     * @return {@link AbstractAggregationBuilder}
     **/
//    private AbstractAggregationBuilder<TermsAggregationBuilder> getEChartAggregationBuilder(RequirementPlanDTO requirementPlanDTO) {
//        //计划开始日期分组（必然分组）
//        TermsAggregationBuilder termDate = AggregationBuilders.terms(GROUP_DATE.getType())
//                .field(FORMULATE_DATE.getType()).size(Integer.MAX_VALUE).shardSize(Integer.MAX_VALUE);
//        termDate.subAggregation(AggregationBuilders.sum(GROUP_REQUIREMENT_NUMS.getType()).field(FORECAST_PLAN_QTY.getType()));
//        return termDate;
//    }

    /**
     * 构建es过滤条件
     *
     * @param requirementPlanDTO
     * @return {@link BoolQueryBuilder}
     **/
    private BoolQueryBuilder getBoolQueryBuilder(RequirementPlanDTO requirementPlanDTO) {
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        //渠道过滤条件
        if (requirementPlanDTO.getExistChannel()) {
            queryBuilder.filter(this.getShouldCondition(CHANNEL.getType(), requirementPlanDTO.getFatherChannelCodeList()));
        }
        //品类过滤条件
        if (requirementPlanDTO.getExistPriCate()) {
            queryBuilder.filter(this.getShouldCondition(CATE_L2.getType(), requirementPlanDTO.getPriCategoryCodeList()));
        }
        if (requirementPlanDTO.getExistSecCate()) {
            queryBuilder.filter(this.getShouldCondition(CATE_L3.getType(), requirementPlanDTO.getSecCategoryCodeList()));
        }
        if (requirementPlanDTO.getExistTerCate()) {
            queryBuilder.filter(this.getShouldCondition(CATE_L4.getType(), requirementPlanDTO.getTerCategoryCodeList()));
        }
        if (requirementPlanDTO.getExistSkuCate()) {
            queryBuilder.filter(this.getShouldCondition(SKU_KEY.getType(), requirementPlanDTO.getSkuCodeList()));
        }
        //区域过滤条件
        if (requirementPlanDTO.getExistPro()) {
            queryBuilder.filter(this.getShouldCondition(PROVINCE.getType(), requirementPlanDTO.getProvinceCodeList()));
        }
        if (requirementPlanDTO.getExistCity()) {
            queryBuilder.filter(this.getShouldCondition(CITY.getType(), requirementPlanDTO.getCityCodeList()));
        }
        if (requirementPlanDTO.getExistCount()) {
            queryBuilder.filter(this.getShouldCondition(DISTRICT.getType(), requirementPlanDTO.getCountyCodeList()));
        }
        if (requirementPlanDTO.getExistStore()) {
            queryBuilder.filter(this.getShouldCondition(NODE_ID.getType(), requirementPlanDTO.getStoreCodeList()));
        }
        //仓库过滤条件
        queryBuilder.filter(this.getShouldCondition(DELIVER_ID.getType(), requirementPlanDTO.getWarehouseCodeList()));
        //日期条件
        queryBuilder.filter(rangeQuery(FORMULATE_DATE.getType()).gte(requirementPlanDTO.getStartDateStr()).lte(requirementPlanDTO.getLastOfStartDateStr()));
        return queryBuilder;
    }

    private BoolQueryBuilder getShouldCondition(String element, List<String> codes) {
        BoolQueryBuilder tempQueryBuilder = QueryBuilders.boolQuery();
        codes.forEach(item -> tempQueryBuilder.should(matchQuery(element, item)));
        return tempQueryBuilder;
    }

    /**
     * 导出excel
     *
     * @param requirementPlanDTO 需求计划dto
     * @param type               类型
     */
    @Override
    public ExcelExportDataDTO exportExcel(RequirementPlanDTO requirementPlanDTO, Integer type) {
        //指标名称集合
        List<String> allTargetsDesc = RequirementPlanTargetEnum.getAllTargetsDesc();
        //获取日期标题
        List<String> dateTitles = MyDateUtil.processCyclesDate(requirementPlanDTO.getWeekDateList(), "MM.dd");
        List<RequirementPlanInfoDTO> requirementPlanInfoDTOList = new ArrayList<>();
        List<List<Object>> exportDataList = null;
        Long userId = requirementPlanDTO.getCreator();
        //获取当前用户角色权限
        List<RoleAuthorityAreaDTO> roleAreaList = roleAuthorityAreaRepository.listByUserId(userId);
        if (CollectionUtils.isEmpty(roleAreaList)) {
            throw new RomeException(ResponseMsg.FAIL_2004.getCode(), ResponseMsg.FAIL_2004.getMsg());
        }
        //渠道不为空为其他渠道计划用户
        roleAreaList = roleAreaList.stream().filter(item -> ObjectUtil.isNotNull(item.getChannelCode())).collect(Collectors.toList());
        List<String> channels = new ArrayList<>();
        roleAreaList.forEach(item -> {
            String channel = item.getChannelCode();
            channels.add(channel);
        });
        //高级搜索不选择渠道，查询用户对应渠道
        if (CollectionUtils.isEmpty(requirementPlanDTO.getFatherChannelCodeList())) {
            requirementPlanDTO.setFatherChannelCodeList(channels);
        }
        //当前页数据导出&&全部数据导出
        if (ExcelExportTypeEnum.CURRENT_PAGE_EXPORT.getType().equals(type)
                || ExcelExportTypeEnum.SEARCHED_DATA_EXPORT.getType().equals(type)) {
            PageInfo<RequirementPlanInfoDTO> pageInfo = this.listWeekBySelective(requirementPlanDTO);
            requirementPlanInfoDTOList = pageInfo.getList();
        }
        // TODO: 2020/11/3 导出选中的数据
/*        if (ExcelExportTypeEnum.CHECKED_BOX_EXPORT.getType().equals(type)) {
            DemandPlanDO demandPlanDO = dealData(demandPlanConvertor.dtoToDO(demandPlanDTO.getDemandPlanDTOS()), demandPlanDTO);
            demandPlanDTOList = demandPlanRepository.listSalesAndDirectTarget(demandPlanDO);
        }*/
        if (CollectionUtils.isEmpty(requirementPlanInfoDTOList)) {
            throw new RomeException(ResponseMsg.FAIL_2005.getCode(), ResponseMsg.FAIL_2005.getMsg());
        }
        //全部数据导出
        exportDataList = this.getExcelTargetList(requirementPlanInfoDTOList, allTargetsDesc, dateTitles);
        //获取excel标题 同时返回高级搜索标题的数量
        List<List<String>> heads = new ArrayList<>();
        int mergeCellsColumns = this.setExcelTitles(heads, dateTitles);
        return ExcelExportUtil.getExcelExportData(mergeCellsColumns, exportDataList, heads, allTargetsDesc.size(), new GeneralCellWriteHandler());
    }

    /**
     * Excel中的每条数据
     *
     * @param targetList
     * @param targets
     * @param dateTitles
     * @return
     */
    private List<List<Object>> getExcelTargetList(List<RequirementPlanInfoDTO> targetList, List<String> targets, List<String> dateTitles) {
        //获取excel数据
        List<List<Object>> exportDataList = new ArrayList<>();
        targetList.forEach(item -> {
            for (int i = 0; i < targets.size(); i++) {
                List<Object> itemRow = new ArrayList<>();
                //加入渠道，仓库，区域，品类，商品  信息
                this.setExcelRowAdvancedSearchCondition(item, itemRow);
                //加入指标
                String targetName = targets.get(i);
                itemRow.add(targetName);
                //加入数据，设置每周的值
                for (int j = 0; j < dateTitles.size(); j++) {
//                    if (RequirementPlanTargetEnum.SALES_PLAN_AMOUNT.getDesc().equals(targetName)) {
//                        itemRow.add(item.getSalesPlanAmount().get(j).compareTo(BigDecimal.ZERO) == 0 ? "-" : item.getSalesPlanAmount().get(j));
//                    } else if (RequirementPlanTargetEnum.FORECAST_PLAN_AMOUNT.getDesc().equals(targetName)) {
//                        itemRow.add(item.getForecastPlanAmount().get(j).compareTo(BigDecimal.ZERO) == 0 ? "-" : item.getForecastPlanAmount().get(j));
//                    } else
                    if (RequirementPlanTargetEnum.SALES_PLAN_QTY.getDesc().equals(targetName)) {
                        itemRow.add(item.getSalesPlanQty().get(j).compareTo(BigDecimal.ZERO) == 0 ? "-" : item.getSalesPlanQty().get(j));
                    } else if (RequirementPlanTargetEnum.FORECAST_PLAN_QTY.getDesc().equals(targetName)) {
                        itemRow.add(item.getForecastPlanQty().get(j).compareTo(BigDecimal.ZERO) == 0 ? "-" : item.getForecastPlanQty().get(j));
                    } else if (RequirementPlanTargetEnum.SAFETY_STOCK_QTY.getDesc().equals(targetName)) {
                        itemRow.add(item.getStockSafety().get(j).compareTo(BigDecimal.ZERO) == 0 ? "-" : item.getStockSafety().get(j));
                    } else if (RequirementPlanTargetEnum.SUPPLY_CHAIN_CONFIRMATION_QTY.getDesc().equals(targetName)) {
                        itemRow.add(item.getSupChainConfirmQty().get(j).compareTo(BigDecimal.ZERO) == 0 ? "-" : item.getSupChainConfirmQty().get(j));
                    } else if (RequirementPlanTargetEnum.SALE_PLAN_CONFIRMATION_QTY.getDesc().equals(targetName)) {
                        itemRow.add(item.getSalePlanConfirmationQty().get(j).compareTo(BigDecimal.ZERO) == 0 ? "-" : item.getSalePlanConfirmationQty().get(j));
                    } else if (RequirementPlanTargetEnum.LAST_CONFIRM_QTY.getDesc().equals(targetName)) {
                        itemRow.add(item.getLastConfirmQty().get(j).compareTo(BigDecimal.ZERO) == 0 ? "-" : item.getLastConfirmQty().get(j));
                    } else if (RequirementPlanTargetEnum.LAST_SALE_PLAN_CONFIRM_QTY.getDesc().equals(targetName)) {
                        itemRow.add(item.getLastSalePlanConfirmQty().get(j).compareTo(BigDecimal.ZERO) == 0 ? "-" : item.getLastSalePlanConfirmQty().get(j));
                    } else if (RequirementPlanTargetEnum.RESERVE_PURCHASE_QTY.getDesc().equals(targetName)) {
                        itemRow.add(item.getReservePurchaseQty().get(j).compareTo(BigDecimal.ZERO) == 0 ? "-" : item.getReservePurchaseQty().get(j));
                    } else if (RequirementPlanTargetEnum.ACTUAL_SALES_QTY.getDesc().equals(targetName)) {
                        itemRow.add(item.getActualSalesQty().get(j).compareTo(BigDecimal.ZERO) == 0 ? "-" : item.getActualSalesQty().get(j));
                    } else if (RequirementPlanTargetEnum.NO_FULFIL_PURCHASE_QTY.getDesc().equals(targetName)) {
                        itemRow.add(item.getNoFulfilPurchaseQty().get(j).compareTo(BigDecimal.ZERO) == 0 ? "-" : item.getNoFulfilPurchaseQty().get(j));
                    } else if (RequirementPlanTargetEnum.REAL_TIME_INVENTORY.getDesc().equals(targetName)) {
                        itemRow.add(item.getRealTimeInventory().get(j).compareTo(BigDecimal.ZERO) == 0 ? "-" : item.getRealTimeInventory().get(j));
                    }
                }
                exportDataList.add(itemRow);
            }
        });
        return exportDataList;
    }

    /**
     * excel每行数据设置 高级搜索  信息
     *
     * @param requirementPlanInfoDTO
     * @param itemRow
     * @return void
     **/
    private void setExcelRowAdvancedSearchCondition(RequirementPlanInfoDTO requirementPlanInfoDTO, List<Object> itemRow) {
        itemRow.add(requirementPlanInfoDTO.getChannel());
        itemRow.add(requirementPlanInfoDTO.getWarehouseName());
        itemRow.add(requirementPlanInfoDTO.getArea());
        itemRow.add(requirementPlanInfoDTO.getCategory());
        itemRow.add(requirementPlanInfoDTO.getSkuName() + "/" + requirementPlanInfoDTO.getSkuCode());
    }

    private int setExcelTitles(List<List<String>> heads, List<String> dateTitles) {
        //获取高级搜索标题
        this.getExcelAdvancedSearchTitle(heads);
        int result = heads.size();
        //加入指标标题
        List<String> targetTitle = new ArrayList<>();
        targetTitle.add(ExcelExportTitleEnum.TARGET_TITLE.getTitle());
        heads.add(targetTitle);
        //加入日期标题
        AdvancedSearchUtil.getExcelDateTitle(heads, dateTitles);
        return result;
    }

    /**
     * Excel表头
     *
     * @param heads
     */
    private void getExcelAdvancedSearchTitle(List<List<String>> heads) {
        setList(heads, ExcelExportTitleEnum.CHANNEL_TITLE.getTitle());
        setList(heads, ExcelExportTitleEnum.WAREHOUSE.getTitle());
        setList(heads, ExcelExportTitleEnum.AREA_TITLE.getTitle());
        setList(heads, ExcelExportTitleEnum.CATEGORY_TITLE.getTitle());
        setList(heads, ExcelExportTitleEnum.SKU_TITLE.getTitle());
    }

    /**
     * 获取标题行list
     *
     * @param heads
     * @param title
     */
    private static void setList(List<List<String>> heads, String title) {
        List<String> list = new ArrayList<>();
        list.add(title);
        heads.add(list);
    }

    @Override
    public void test() {
        //TODO 前端传字符串
//        String afterKey = "";
//        do {
//            //执行api调用
//            afterKey = doSomething();
//        } while (afterKey != null);
        //构建查询
        List<CompositeValuesSourceBuilder<?>> sources = new ArrayList<>();
        Script script = new Script("doc['deliver_id'].values +'####'+doc['province'].values+'####'+doc['sku_key'].values");
        TermsValuesSourceBuilder dataBuilder = new TermsValuesSourceBuilder("multiGroup").script(script);
        sources.add(dataBuilder);

        CompositeAggregationBuilder comAgg = new CompositeAggregationBuilder("aggs1", sources);
        comAgg.size(2);


        Map<String, Object> afterKey = new HashMap<>();
        afterKey.put("multiGroup", null);
        comAgg.aggregateAfter(afterKey);
        TermsAggregationBuilder groupDate = AggregationBuilders.terms("group_son").script(new Script("doc['start_date'].values")).size(2000);
        groupDate.subAggregation(AggregationBuilders.sum("sum_score").script(new Script("doc['predict_sales'].value")));
        groupDate.subAggregation(AggregationBuilders.avg("avg_score").script(new Script("doc['predict_sales'].value")));
        comAgg.subAggregation(groupDate);
        SearchQuery query = new NativeSearchQueryBuilder().withPageable(PageRequest.of(0, 1))
                .withIndices("test")
                .addAggregation(comAgg)
                .build();
        //解析
        AggregatedPage<TestEsEntity> entities = elasticsearchTemplate.queryForPage(query, TestEsEntity.class);
        CompositeAggregation parsedComposite = entities.getAggregations().get("aggs1");
        if (parsedComposite.afterKey() == null) {
            //到最后了
        }
        System.out.println(parsedComposite.afterKey().get("multiGroup"));
        List<? extends CompositeAggregation.Bucket> list = parsedComposite.getBuckets();
        for (CompositeAggregation.Bucket parsedBucket : list) {
            //键值对存放所有分组条件
            for (Map.Entry<String, Object> m : parsedBucket.getKey().entrySet()) {
            }
            Aggregation subAggregations = parsedBucket.getAggregations().asMap().get("group_son");
            StringTerms stringTerms = (StringTerms) subAggregations;
            List<StringTerms.Bucket> bb = stringTerms.getBuckets();
            for (StringTerms.Bucket element : bb) {
                System.out.println(element.getKey().toString());
                InternalSum internalSum = element.getAggregations().get("sum_score");
                InternalAvg internalAvg = element.getAggregations().get("avg_score");
                System.out.println(internalSum);
                System.out.println(internalSum);
            }
            System.out.println(bb);
        }
    }
}
